package com.cctc.juc.demo.Bitc.Epipeline.Exchanger;

import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 官方概述：一个同步点，线程可以在该点配对和交换成对中的元素。
 * 每个线程在进入 exchange 方法时都会显示一些对象，与伙伴线程匹配，并在返回时接收其伙伴的对象。
 * 交换器可以被视为 SynchronousQueue 的双向形式。
 * 交换器在遗传算法和管道设计等应用中可能很有用。
 */
public class ExchangerDemo {

    /**
     * 线程间通信方式之使用 Exchanger 数据交换器：两个线程之间进行数据交换。
     * - Exchanger [数据交换器] 是一个常用的线程间数据通信工具。在每个线程在完成当前事务后想与对方交换数据时，第一个先拿出数据的线程将一直等到第二个线程拿着数据到来时，才彼此交换数据。
     * 核心方法：
     * - public Exchanger();
     * - public V exchange(V x) throws InterruptedException;
     * - public V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException;
     * 使用步骤：
     * 1）调用构造器，创建 [数据交换器]，指定需要交换的数据类型 <V>;
     * 2）当线程 A 到达交换点时，调用 Exchanger.exchange(V x) 方法，拿出数据，进行自我等待，等待线程 B 也调用了
     * Exchanger.exchange(V x) 方法，也拿出数据，然后 Exchanger 将以线程安全的方式交换彼此的数据，交换完成后，线程 A 和 B 各自继续向下执行。
     */

    public static void main(String[] args) {
        final Exchanger<String> exchanger = new Exchanger<>();

        ExecutorService service = Executors.newCachedThreadPool();

        service.execute(() -> {
            try {
                String data1 = "张三";
                System.out.println(Thread.currentThread().getName() + " 线程，正在把数据 [" + data1 + "] 交换出去！！！");

                Thread.sleep(ThreadLocalRandom.current().nextInt(3000));

                String data2 = exchanger.exchange(data1);
                System.out.println(Thread.currentThread().getName() + " 线程，交换回的数据为 [" + data2 + "]，继续向下运行...");

                Thread.sleep(ThreadLocalRandom.current().nextInt(1000));

                System.out.println(Thread.currentThread().getName() + " 线程，运行结束！！！");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });

        service.execute(() -> {
            try {
                String data1 = "李四";
                System.out.println(Thread.currentThread().getName() + " 线程，正在把数据 [" + data1 + "] 交换出去！！！");
                Thread.sleep(ThreadLocalRandom.current().nextInt(3000));

                String data2 = exchanger.exchange(data1);
                System.out.println(Thread.currentThread().getName() + " 线程，交换回的数据为 [" + data2 + "]，继续向下运行...");

                Thread.sleep(ThreadLocalRandom.current().nextInt(1000));

                System.out.println(Thread.currentThread().getName() + " 线程，运行结束！！！");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });

        service.shutdown();
    }
}
